using System;
using System.Collections.Generic;
using AutoChess.Map;
using JetBrains.Annotations;
using UnityEngine;

namespace AutoChess
{
    class ActorManager:BaseLogicSys<ActorManager>
    {
        private Dictionary<long,GameActor> m_actorPool = new Dictionary<long, GameActor>();
        private Dictionary<int,GameActor> m_goModelHash2Actor = new Dictionary<int, GameActor>();
        
        private List<GameActor> m_listActor = new List<GameActor>();
        private List<GameActor> m_listDestroyActor = new List<GameActor>();

        /// <summary>
        /// 附属召唤物，key是英雄的svrActorId
        /// </summary>
        private Dictionary<long,List<GameActor>> m_dicOwnActor = new Dictionary<long, List<GameActor>>();
        
        private Transform m_actorRootTrans = null;

        public Transform ActorRootTrans
        {
            get { return m_actorRootTrans; }
        }

        private long m_selectedId;
        
        public ActorManager()
        {
            GameEvent.AddListener<GameActor>(IActorLogic_Event.OnActorDie,OnActorDie);
            MapDataMgr.Instance.OnLeaveMap += OnLeaveMap;
        }

        protected override bool OnInit()
        {
           ActorRenderMgr.Instance.Init();

           SceneSys.Instance.OnEnterScene += ActorRenderMgr.Instance.OnSceneLoaded;
           return true;
        }

        #region 外部调用接口
        
        public GameActor GetActorByActorId(uint actorId)
        {
            GameActor actor;
            if (m_actorPool.TryGetValue(actorId, out actor))
            {
                return actor;
            }

            return null;
        }

        public GameActor GetActor(GameObject go)
        {
            GameActor actor;
            if (m_goModelHash2Actor.TryGetValue(go.GetHashCode(), out actor))
            {
                return actor;
            }

            return null;
        }

        #endregion

        #region 流程接口

        public ACHero CreateACHero(HeroData heroData)
        {
            var actor = new ACHero();
            PrepareCreatedActor(actor,heroData.svrId,heroData.svrId,heroData.GetBattleSide());
            
            if(!actor.CreateACActor(heroData))
            {
                BLogger.Error("create autoChessHero actor failed: {0}",heroData.chessId);
                DestroyActor(actor);
                return null;
            }
            
            actor.EnterMap();
            return actor;
        }

        public ACGrid CreateACGrid(ACGridData gridData)
        {
            var actor = new ACGrid();
            PrepareCreatedActor(actor,gridData.localIndex,gridData.localIndex,BattleSide.None);

            if (!actor.CreateACGrid(gridData))
            {
                BLogger.Error("create autoChessHero actor failed: Grid:{0}:Index:{1}",
                    gridData.gridType,gridData.localIndex);
                DestroyActor(actor);
                return null;
            }
            
            actor.EnterMap();
            return actor;
        }

        private void BindGameActorGo(GameActor actor, GameObject go)
        {
            m_goModelHash2Actor[go.GetHashCode()] = actor;
        }

        /// <summary>
        /// 创建基础组件
        /// </summary>
        private void PrepareCreatedActor(GameActor actor, long svrActorId, int ownSvrActorId,BattleSide side)
        {
            actor.CreateActorBase(svrActorId , ownSvrActorId,side);

            if (svrActorId != 0)
            {
                m_actorPool.Add(svrActorId,actor);
            }
            m_listActor.Add(actor);
            BindGameActorGo(actor, actor.ActorTrans.ActorGO);
        }

        public void ClearActors()
        {
            var listToDel = new List<GameActor>();
            var listActor = m_listActor;
            for (int i = 0; i < listActor.Count; i++)
            {
                var actor = listActor[i];
                listToDel.Add(actor);
            }

            for (int i = 0; i < listToDel.Count; i++)
            {
                var delActor = listToDel[i];
                DestroyActor(delActor);
            }
            
            listToDel.Clear();
            m_dicOwnActor.Clear();
            m_listDestroyActor.Clear();
            m_selectedId = 0;
        }

        public void DestroyActor(GameActor actor)
        {
            if (actor.OwnSvrActorId != 0 && actor.SvrActorId == 0)
            {
                List<GameActor> listActor;
                if (m_dicOwnActor.TryGetValue(actor.OwnSvrActorId, out listActor))
                {
                    listActor.Remove(actor);
                }
            }

            m_goModelHash2Actor.Remove(actor.ActorTrans.ActorGO.GetHashCode());
            actor.Destroy();

            if (actor.SvrActorId != 0)
            {
                m_actorPool.Remove(actor.SvrActorId);
            }

            m_listActor.Remove(actor);
        }

        #endregion
        
        #region event

        public void OnActorDie(GameActor actor)
        {
            float deathTime = actor.Display.GetDeathTime();
            actor.DestoryTime = BattleTime.time + deathTime;
        }

        public void OnLeaveMap()
        {
            ClearActors();
        }

        #endregion

        #region 流程接口

        protected override void OnUpdate()
        {
            float currTime = BattleTime.time;
            bool ret = false;
            for (int i = 0; i < m_listActor.Count; i++)
            {
                GameActor actor = m_listActor[i];
                actor.Update();

                if (actor.DestoryTime > 0f && actor.DestoryTime <= currTime)
                {
                    m_listDestroyActor.Add(actor);
                    ret = true;
                }
            }

            if (!ret)
            {
                return;
            }

            for (int i = 0; i < m_listDestroyActor.Count; i++)
            {
                DestroyActor(m_listDestroyActor[i]);
            }
            m_listDestroyActor.Clear();
        }

        protected override void OnLateUpdate()
        {
            for (int i = 0; i < m_listActor.Count; i++)
            {
                m_listActor[i].LateUpdate();
            }
        }

        #endregion
    }
}